#include<iostream>
#include<opencv2/imgcodecs.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
#include<opencv2/objdetect.hpp>
#include<string>
#include<vector>

using namespace std;
using namespace cv;

Mat imgOriginal, imgCanny,imgThre,imgGray,imgBlur,imgDil,imgErode,imgWarp,imgCrop;
vector<Point> initialPoints,docPoints;

float w=420,h=596;

//////////////////////////////////问题在此函数中////////////////////////////////////////////
//////////////////////////////////以下没有问题///////////////////////////////////////////////
vector<Point> getContours(Mat image)//获取最大四边形轮廓函数
{
    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;

    findContours(image,contours,hierarchy,RETR_EXTERNAL,CHAIN_APPROX_SIMPLE);

    vector<vector<Point>>conPoly(contours.size());
    vector<Rect>boundRect(contours.size());

    vector<Point>biggest;
    int maxArea;

    for(int i=0;i<contours.size();i++)
    {
        int area=contourArea(contours[i]);
        cout<<area<<endl;//能找到区域


        string objectType;

        if(area>1000)
        {

            float peri=arcLength(contours[i],true);
            approxPolyDP(contours[i],conPoly[i],0.02*peri,true);
            ///////////////////////以上没有问题/////////////////////////////////////////////////

            ///////////////////////////////////////问题在下面////////////////////////////////////////
            if(conPoly[i].size()==4 && area>maxArea )//此判断中（area>maxArea && ）可能导致biggest无法赋值,用图片测试时需要屏蔽
            {
                drawContours(imgOriginal,conPoly,i,Scalar(255,0,255),5);
                biggest={conPoly[i][0],conPoly[i][1],conPoly[i][2],conPoly[i][3]};
                maxArea=area;
            

                // cout<<conPoly[i].size()<<endl;
                // boundRect[i]=boundingRect(conPoly[i]);
                // myPoint.x=boundRect[i].x+boundRect[i].width/2;
                // myPoint.y=boundRect[i].y;

               
            }
            /////////////////////////////////问题在上面///////////////////////////////////////////
 
            //rectangle(imgOriginal,boundRect[i].tl(),boundRect[i].br(),Scalar(0,255,0),5);            
        }
    }
    return biggest;
}


////////////////////////////////////////////////此函数没有问题/////////////////////////////////////////////////
Mat preProcessing(Mat img)//图像预处理函数
{
    cvtColor(img,imgGray,COLOR_BGR2GRAY);
    GaussianBlur(imgGray,imgBlur,Size(3,3),3,0);
    Canny(imgBlur,imgCanny,25,75);

    Mat kernel=getStructuringElement(MORPH_RECT,Size(3,3));
    dilate(imgCanny,imgDil,kernel);
    // erode(imgDil,imgErode,kernel);
    return imgDil;
}
//////////////////////////////////////////////////此函数没有问题///////////////////////////////////////////

/////////////////////////////////////此函数没有问题///////////////////////////////////////
void drawPoints(vector<Point> points,Scalar color)//画点函数
{
    for(int i=0;i<points.size();i++)
    {
        circle(imgOriginal,points[i],10,color,FILLED);
        putText(imgOriginal,to_string(i),points[i],FONT_HERSHEY_PLAIN,2,color,2);

    }
}
///////////////////////////////////此函数没有问题//////////////////////////////////////

vector<Point> reorder(vector<Point>points)//重新标点函数
{
    vector<Point> newPoints;
    vector<int> sumPoints,subPoints;
    
    for(int i=0;i<4;i++)
    {
        sumPoints.push_back( points[i].x+points[i].y );
        subPoints.push_back( points[i].x-points[i].y );
    }

    newPoints.push_back(points[ min_element(sumPoints.begin(),sumPoints.end())-sumPoints.begin() ] );
    newPoints.push_back(points[ max_element(subPoints.begin(),subPoints.end())-subPoints.begin() ] );
    newPoints.push_back(points[ min_element(subPoints.begin(),subPoints.end())-subPoints.begin() ] );
    newPoints.push_back(points[ max_element(sumPoints.begin(),sumPoints.end())-sumPoints.begin() ] );

    return newPoints;

}

Mat getWarp(Mat img,vector<Point>points,float w,float h)//图像扭曲函数
{
    Point2f src[4]={points[0],points[1],points[2],points[3]};
    Point2f dst[4]={{0.0f,0.0f},{w,0.0f},{0.0f,h},{w,h}};

    Mat matrix=getPerspectiveTransform(src,dst);
    warpPerspective(img,imgWarp,matrix,Point(w,h));

    return imgWarp;
}

int main()
{
    VideoCapture cap(0);


    // string path="/home/zhanjiabin/桌面/task/documentscanner/paper.jpg";
    // imgOriginal=imread(path);
    // resize(imgOriginal,imgOriginal,Size(),0.1,0.1);

    while(true)
    {
        cap.read(imgOriginal);
        //图像预处理
        imgThre = preProcessing(imgOriginal);

        //获得最大四边形轮廓
        initialPoints = getContours(imgThre);

        if(initialPoints.empty())//若无法找到四边形轮廓未能给initialPoints = biggest赋值则直接显示这一帧画面不做处理，防止访问空指针
        {
            imshow("Image",imgOriginal);
            waitKey(1);
        }
        else//只有在找到四边形轮廓并成功给initialPoints = biggest赋值才对图像进行处理
        {
            //drawPoints(initialPoints,Scalar(0,0,255));
            docPoints = reorder(initialPoints);//重新标点
            drawPoints(docPoints,Scalar(0,255,0));

            //图像扭曲
            imgWarp=getWarp(imgOriginal,docPoints,w,h);

            //图像剪裁
            int cropVal=5;
            Rect roi(cropVal,cropVal,w-(2*cropVal),h-(2*cropVal));
            imgCrop=imgWarp(roi);
            imshow("Image Crop",imgCrop); 
            imshow("Image",imgOriginal);
            waitKey(1);

        }



        
        // imshow("Dil",imgThre); 
        // imshow("Image Warp",imgWarp);
         
        
    }
    
    return 0;
}